#include <iostream>
#include <string>
#include <thread>
#include <unistd.h>
#include <cstdlib>
#include <ctime>
#include "mqtt/async_client.h"

const std::string SERVER_ADDRESS("tcp://broker.emqx.io:1883"); // 公共MQTT服务器地址和端口
const std::string CLIENT_ID("ShrMqttTest_20241218_PublishClient"); // 客户端ID
const std::string TOPIC("20241218/MqttTest/topic"); // 订阅的主题

// 继承mqtt::callback类，自定义相关回调函数
class Callback : public mqtt::callback
{
public:
   Callback(mqtt::async_client* cl)
      :client(cl)
   {}

private:
   void connected(const std::string& cause) override // 客户端连接服务器成功
   {
      std::cout << "Connected to the MQTT server..." << std::endl;
      client->subscribe(TOPIC, 1); // 直接订阅主题
   }

   void connection_lost(const std::string& cause) override // 客户端与服务器断开连接
   {
      std::cout << "Connection lost: " << cause << std::endl;
   }

   void message_arrived(mqtt::const_message_ptr msg) override // 消息到达客户端
   {
      std::cout << "Message arrived, topic: " << msg->get_topic()
               << " , payload: " << msg->to_string() << std::endl;
   }

   void delivery_complete(mqtt::delivery_token_ptr token) override // 消息投递到服务器完成
   {
      std::cout << "Delivery complete..." << std::endl;
   }

private:
   mqtt::async_client* client;
};

void send_random_message(mqtt::async_client& client, const std::string& topic)
{
   while (true)
   {
      sleep(1); // 每秒发送一次消息
      // 生成长度随机、内容随机的payload
      int length = rand() % 100 + 1;
      std::string payload(length, ' ');
      for (int i = 0; i < length; ++i) {
         payload[i] = 'a' + (rand() % 26);
      }

      mqtt::message_ptr pubmsg = mqtt::make_message(topic, payload);
      pubmsg->set_qos(1); // 设置QoS为1 -> 至少一次
      client.publish(pubmsg); // publish消息
   }
}

int main()
{
   srand(static_cast<unsigned int>(time(nullptr)));

   mqtt::async_client client(SERVER_ADDRESS, CLIENT_ID); // 实例化MQTT客户端
   Callback cb(&client); // 实例化自定义的回调方法类
   client.set_callback(cb); // 设置回调方法类

   mqtt::connect_options conopts; // 设置连接选项
   conopts.set_clean_session(true); // 清除会话标志位 -> 丢弃之前的会话状态, 开启一个新会话

   std::cout << "Connecting to the MQTT server..." << std::endl;
   mqtt::token_ptr conntok = client.connect(conopts); // 连接mqtt服务器
   conntok->wait(); // 等待连接结果
   std::cout << "Connected..." << std::endl;

   std::thread sender_thread(send_random_message, std::ref(client), TOPIC);
   sender_thread.join();

   return 0;
}
